<?

/**
 * Klasa FrontControllera
 *
 */
class FrontController {

    private $loadError = false;
    /**
     * Parametry przekazane przez Router
     *
     * @var array
     */
    private $route;
    /**
     * Katalog z kontrolerami
     *
     * @var string
     */
    private $directory = 'controller';
    /**
     * Kontroler do uruchomienia
     *
     * @var string
     */
    private $controller;
    /**
     * Metoda do wywolania
     *
     * @var string
     */
    private $method;
    /**
     * Parametry dla metody
     *
     * @var array
     */
    private $param;
    /**
     * Obiekt kontrolera
     *
     * @var Object
     */
    private $controllerObj;
    /**
     * Domyslny kontroler
     *
     * @var string
     */
    private $defaultController = 'DefaultController';
    /**
     * Konfiguracja kontrolera
     *
     * @var array
     */
    private $config;
    /**
     * Delimiter tytulu strony
     *
     * @var string
     */
    private $titleDelimiter;
    /**
     * Czy tytul ma byc generowany w odwrotnej kolejnosci
     *
     * @var bool
     */
    private $titleReverse = false;
    /**
     * Blokowanie partiali
     * 
     * @var bool
     */
    private $disablePartials;
    
    
    private $templatePath;

    /**
     * Konstruktor
     *
     */
    public function __construct() {
	$this->route = Router::GetParam();
	
	//print_r($this->route);
	if (isset($this->route['controller'])) {
	    $this->controller = ucfirst($this->route['controller']);
	}
	if (isset($this->route['param'])) {
	    $this->param = $this->route['param'];
	}

	if (isset($this->route['method'])) {
	    $this->method = ucfirst($this->route['method']);
	    $this->param['methodToRun'] = $this->method;
	}
	if (isset($this->route['config'])) {
	    $this->config = $this->route['config'];
	}
    }

    /**
     * Zmienia domyslny katalog z kontrolerami
     *
     * @param string $dir
     */
    public function SetDirectory($dir) {
	$this->directory = $dir;
    }

    /**
     * Laduje plik z klasa kontrolera
     *
     */
    private function LoadController() {

	if (is_file($this->directory . '/' . str_replace('_', '/', ucfirst($this->controller)) . '.php')) {
	    $this->templatePath = $this->controller;
	    Core::RequireOnce($this->directory . '/' . str_replace('_', '/', ucfirst($this->controller)) . '.php');
	    Core::RequireOnce($this->directory . '/SharedController.php');
	} else {
	    Core::RequireOnce($this->directory . '/' . ucfirst($this->defaultController) . '.php');
	    Core::RequireOnce($this->directory . '/SharedController.php');
	    $this->templatePath = $this->controller;
	    $this->controller = $this->defaultController;
	    $this->loadError = true;
	}
    }

    /**
     * Laduje plik z klasa kontrolera
     *
     */
    private function LoadModule() {
	if (is_file($this->directory . '/' . $this->config['module'] . '/' . str_replace($this->config['module'] . '_', '', ucfirst($this->controller)) . '.php')) {
	    Core::RequireOnce($this->directory . '/' . $this->config['module'] . '/' . str_replace($this->config['module'] . '_', '', ucfirst($this->controller)) . '.php');
	    Core::RequireOnce($this->directory . '/SharedController.php');
	    MFLog::Debug('Loading module: ' . $this->config['module'] . ': ' . $this->controller);
	} else {
	    Core::RequireOnce($this->directory . '/' . ucfirst($this->defaultController) . '.php');
	    Core::RequireOnce($this->directory . '/SharedController.php');
	    $this->controller = $this->defaultController;
	    MFLog::Debug('Unable to load module, Loading controller: ' . $this->controller);
	}
    }

    /**
     * Uruchamia obiekt kontrolera
     *
     */
    private function RunController() {
	$exp = explode('_', $this->controller);

	$className = $this->controller;

	if ($this->ValidControllerClass($className)) {
	    $this->controllerObj = new $className();
	    $method = $this->method;

	    if ((!method_exists($this->controllerObj, $method) && !method_exists($this->controllerObj, $method . 'Action'))) {
		$this->method = 'Index';
	    }
	    if ($this->loadError && ($this->method == 'Index' && $this->route['param']['urlParam'] != '')) {
		$this->method = 'Error404';
	    }
	} else {
	    throw new Exception('Brak klasy lub brak dziedziczenia!');
	}
    }

    /**
     * Uruchamia obiekt modulu
     *
     */
    private function RunModule() {
	$className = $this->controller;

	if ($this->ValidControllerClass($className, true)) {
	    $this->controllerObj = new $className();
	    $method = $this->method;

	    if (!method_exists($this->controllerObj, $method) && !method_exists($this->controllerObj, $method . 'Action')) {
		$this->method = 'Index';
	    }
	} else {
	    throw new Exception('Brak klasy lub brak dziedziczenia!');
	}
    }

    /**
     * Przypisuje delimiter tytulu strony
     *
     * @param string $titleDelimiter
     */
    public function SetTitleDelimiter($titleDelimiter) {
	$this->titleDelimiter = $titleDelimiter;
    }

    /**
     * Dodaje element tytulu strony
     *
     * @param string $title
     */
    public function AddTitle($title) {
	Utils::AddHeader('title', $title, false);
    }

    /**
     * Dodawanie opisu
     *
     * @param unknown_type $desc
     */
    public function AddDescription($desc, $overwrite = false) {
	if ($desc != "")
	    Utils::AddHeader('meta', array('name' => 'description', 'content' => $desc), $overwrite);
    }

    /**
     * Dodawanie keywords
     *
     * @param unknown_type $desc
     */
    public final function AddKeywords($keywords, $overwrite = false) {
	Utils::AddHeader('meta', array('name' => 'keywords', 'content' => $keywords), $overwrite);
    }

    private function GenerateScriptsVar($t) {
	$script = array();

	if ($t && is_array($t) && sizeof($t)) {
	    ksort($t);

	    if (count($t) > 0) {
		foreach ($t as $item) {
//					if (sizeof($prio) > 0) {
//						foreach ($prio as $item) {
		    if ($item['file'] != '' && !preg_match("((http)(.*))", $item['file'])) {
			$item['file'] = URL_STATIC_CONTENT . '/script/' . $item['file'];
		    }
		    $script[] = $item;
//						}
//					}
		}
	    }
	} else {
	    $script = array();
	}

	return $script;
    }

    /**
     * Generuje liste skryptow do wyswietlenia w naglowku
     *
     */
    public function GenerateScripts() {
	$t = Registry::Get('javascript');
	$script = $this->GenerateScriptsVar($t);
	$smarty = Registry::Get('smarty');
	$smarty->assign('javaScript', $script);

	$t = Registry::Get('footerJavascript');
	$script = $this->GenerateScriptsVar($t);
	$smarty = Registry::Get('smarty');
	$smarty->assign('footerJavaScript', $script);
    }

    /**
     * Generuje opis strony
     *
     * @return string
     */
    private function GenerateDescription() {

	$headers = Registry::Get('headers');

	if (isset($headers['description'])) {
	    $desc = $headers['description'];
	    $headers['description'] = null;
	    Registry::Remove('headers');
	    Registry::Set('headers', $headers);
	    if (is_array($desc[0])) {
		return "";
	    } else {
		$desc = strtr($desc[0], "'", "`");
		$desc = stripslashes($desc);
		return $desc;
	    }
	}
    }

    /**
     * Odwraca kolejnosc generowania tytulu strony
     *
     */
    private function ReverseTitle() {
	$headers = Registry::Get('headers');
	$t = $headers['title'];
	if (is_array($t)) {
	    $t = array_reverse($t);
	}
	$headers['title'] = $t;
	Registry::Remove('headers');
	Registry::Set('headers', $headers);
    }

    /**
     * Zmienia parametr generowania tytulu strony
     *
     */
    public function FlipTitle() {
	$this->titleReverse = true;
    }

    /**
     * Generuje tytul strony
     *
     * @return string
     */
    private function GenerateTitle() {
	$headers = Registry::Get('headers');
	$t = $headers['title'];
	if (count($t) > 1) {
	    $title = implode($this->titleDelimiter, $t);
	} else if (count($t) == 1) {
	    $title = $t[0];
	} else {
	    $title = '';
	}
	$headers['title'] = null;
	Registry::Remove('headers');
	Registry::Set('headers', $headers);

	return $title;
    }

    /**
     * Generuje strone
     *
     * @return string
     */
    public function Dispatch() {

	$smarty = Registry::Get('smarty');

	$smarty->assign('controller', strtolower(str_replace('Controller', '', $this->controller)));
	$smarty->assign('method', strtolower($this->method));

	if (is_array($this->param)) {
	    $cacheParam = implode('-', $this->param);
	} else {
	    $cacheParam = $this->method;
	}

	if (isset($_POST)) {
	    foreach ($_POST as $postParam => $postValue) {
		$cacheParam.='-' . $postParam . '-' . $postValue;
	    }
	}

	$cacheParam = md5($cacheParam);

	if (isset($this->config['module']) && $this->config['module'] != '') {
	    $this->LoadModule();
	    $this->RunModule();
	    $partialPath = ucfirst($this->config['module']) . '/';
	    $executeAdditional = true;
	    if (isset($this->config['actionSet']) && is_array($this->config['actionSet'])) {
		$this->controllerObj->SetActionSet($this->config['actionSet']);
	    }
	} else {
	    $partialPath = null;
	    $this->LoadController();
	    $this->RunController();
	    $executeAdditional = false;
	    if (isset($this->config['actionSet']) && is_array($this->config['actionSet'])) {
		$this->controllerObj->SetActionSet($this->config['actionSet']);
		$executeAdditional = true;
	    }
	}

	$method = $this->method;

	$this->controllerObj->SetSmarty($smarty);
	$this->controllerObj->partialTemplate = $method . '.tpl';

	$templatePartialPath = null;
	if (isset($this->config['module'])) {
	    $templatePartialPath = $this->config['module'] . '/' . str_replace($this->config['module'] . '_', '', str_replace('Controller', '', $this->controller));
	} else {
	    $templatePartialPath = str_replace('Controller', '', $this->templatePath);
	}
	
	$this->controllerObj->templatePath = 'partial/' . str_replace('_', '/', $templatePartialPath) . '/';

	$this->controllerObj->setRender(isset($this->config['render']) ? strtolower($this->config['render']) : '');

	if (isset($this->config['render']) && ($this->config['render'] == 'validator' || $this->config['render'] == 'no')) {
	    $this->disablePartials = true;
	    $this->param['validate_data'] = array();
	    $smarty->assign('id_form', Request::IsGet('id_f') ? Request::GetGet('id_f') : null);
	    $true = true;
	    Registry::Set(Controller::DESCRIPTION_SET, $true);
	    Registry::Set(Controller::TITLE_SET, $true);
	    header('Content-Type: text/javascript;');
	}



	//obsługa tabów z poziomu routera
	$menu_tab = isset($this->config['menu_tab'])?$this->config['menu_tab']:'index';
	Registry::Set('menu_tab',$menu_tab);
	
	$this->controllerObj->preDispatch($this->param);

	//po predispie bo w predispie jest Run w którym jest logowanko
	$no_action = $this->controllerObj->RestrictedAccess($this->param, isset($this->config['user_role']) ? $this->config['user_role'] : null);
	//$smarty->cache_lifetime = CacheParam::Get('global');




	


	if ($this->controllerObj->GetActionRedirect() != true && $this->controllerObj->GetActionRedirect() != false) {
	    $method = $this->controllerObj->GetActionRedirect();
	}

	$initMethod = $method . 'Init';

	if (!$no_action) {

	    if (method_exists($this->controllerObj, $initMethod)) {
		$this->controllerObj->$initMethod($this->param);
	    }

	    if ((!$this->controllerObj->Init($method, $cacheParam) || $this->controllerObj->CheckLiveMethod($method, $this->param)) && $this->controllerObj->GetActionRedirect() != true) {

		if ($this->controllerObj->CheckLiveMethod($method, $this->param)) {
		    $smarty->cache_lifetime = 0;
		}


		$methodAction = $method . 'Action';
		$this->controllerObj->$methodAction($this->param);
		$methodRun = true;
		Registry::Set('methodRun', $methodRun);
	    } else {
		$cachedMethod = $method . 'Cached';

		if (method_exists($this->controllerObj, $cachedMethod)) {
		    $this->controllerObj->$cachedMethod($this->param);
		}
	    }
	
	    $this->CheckAllMetaHeaders($this->controller, $method);
	}
	$redirectArray = $this->controllerObj->GetRedirect();

	if ($executeAdditional == true) {
	    $this->controllerObj->ExecuteAdditionalActions($this->param);
	}

	if (!isset($this->controllerObj->content) && ($redirectArray['time'] === '' || ($redirectArray['time'] !== '' && $redirectArray['time'] > 0)) && !$this->disablePartials) {

	    $smarty->assign('breadCrumbs', $this->controllerObj->GetBreadCrumbs());

	    //$smarty->cache_lifetime = $this->controllerObj->cacheTime;
	    //echo $smarty->cache_lifetime;
	    $hash = md5($method . $cacheParam);
	    $template = $this->controllerObj->templatePath . $this->controllerObj->partialTemplate;

//	   		die($template);
	    $content = $smarty->fetch($template, $hash);

	    $this->controllerObj->content = $content;

	    //echo $this->controllerObj->templatePath.$this->controllerObj->partialTemplate;
	}


	$smarty->assign('content', $this->controllerObj->content);

	$this->controllerObj->postDispatch($this->param);

	$redirectArray = $this->controllerObj->GetRedirect();

	$smarty->assign('headerRedirect', $redirectArray);

	if (isset($redirectArray['time']) && $redirectArray['time'] == 0 && isset($redirectArray['url']) && $redirectArray['url'] != '') {
	    // Header('Location: '.$redirectArray['url']);
	    Header('Location: ' . $redirectArray['url'], true, $redirectArray['code']);
	    if (Registry::Exists('__infoFrame')) {
		//zachowanie infoFrame gdy robimy redirect bez info, a info zostało zrobione wczesniej
		$_infoFrame = Registry::Get('__infoFrame');
		if (is_array($_infoFrame)) {
		    $info = $_infoFrame['info'];
		    $type = $_infoFrame['error'];
		    SessionProxy::SetValue("frameInfo", $info);
		    SessionProxy::SetValue("frameType", $type);
		} elseif (is_string($_infoFrame)) {
		    $info = $_infoFrame;
		    $type = false;
		    SessionProxy::SetValue("frameInfo", $info);
		    SessionProxy::SetValue("frameType", $type);
		}
	    }
	    die();
	}

	if (isset($redirectArray['time']) && $redirectArray['time'] == -1 && isset($redirectArray['url']) && $redirectArray['url'] != '') {

	    header('Content-Type: text/html');
	    print '<html><head><meta http-equiv="refresh" content="0;url=' . $redirectArray['url'] . '"/></head></html>';
	    die();
	}

	if ($this->titleReverse == true) {
	    $this->ReverseTitle();
	}
	$smarty->assign('pageTitle', $this->GenerateTitle());
	$smarty->assign('pageDescription', $this->GenerateDescription());

	$smarty->assign('pageHeaders', Registry::Get('headers'));





	$this->GenerateScripts();
//echo $smarty->cache_lifetime;
	$template = Registry::Get('smartyTemplate');

	if (Config::Get('SMARTY_INTERNAL_CACHING') == false) {
	    $smarty->caching = Config::Get('SMARTY_CACHING_METHOD');
	}

	if ($this->controllerObj->disableTemplates == false ) {
	    if (!Core::GetAppSafeMode()) {
		//$smarty->CacheControl($template, array('cache_id' => $this->controller . $this->method . md5($cacheParam), 'write' => true, 'methodRun' => true));
		//return $smarty->Display($template, $this->controller.$this->method.md5($cacheParam), $this->controller.$this->method.md5($cacheParam));
		//if($this->controllerObj->CheckLiveMethod($method, $this->param)) {
		//$a = $this->controllerObj->content;
		//} else {
		$a = $smarty->Fetch($template, $this->controller . $this->method . md5($cacheParam));
		//}

		if ($this->controllerObj->utf8) {
		    $a = iconv('iso-8859-2', 'utf-8', $a);
		}

		echo $a;
	    } else {
		//totalny wylot
		Header('Location: ' . Config::Get('FATAL_ERROR_URL'));
	    }
	} else if ($this->controllerObj->disableTemplates == false) {

	    $a = $smarty->Fetch($template, $this->controller . $this->method . md5($cacheParam));
	    if ($this->controllerObj->utf8) {
		$a = iconv('iso-8859-2', 'utf-8', $a);
	    }
	    echo $a;
	}
    }

    /**
     * Sprawdza czy klasa istnieje i ma poprawne dziedziczenie.
     *
     */
    private function ValidControllerClass($className, $module = false) {
	if (!class_exists($className)) {
	    return false;
	}

	if (!class_parents($className) == Array('MainController' => 'MainController', 'Controller' => 'Controller')) {
	    if ($module !== true || !class_parents($className) == Array('ModuleController' => 'ModuleController', 'MainController' => 'MainController', 'Controller' => 'Controller')) {
		return false;
	    }
	}

	if (!class_implements($className) == Array('ControllerInterface' => 'ControllerInterface')) {
	    return false;
	}

	return true;
    }

    private function CheckAllMetaHeaders($controller, $action) {
	if (Config::get('site') == PageType::ADMIN

	    )return;
	if (!Registry::Exists(Controller::DESCRIPTION_SET)

	    )throw new ApiException("Musisz użyć funckji AddDescription w kontrolerze: $controller, w akcji: $action");
	if (!Registry::Exists(Controller::TITLE_SET)

	    )throw new ApiException("Musisz użyć funckji AddTitle w kontrolerze: $controller, w akcji: $action");
	//if(!Registry::Exists(Controller::KEYWORDS_SET))throw new ApiException("Musisz użyć funckji AddKeywords w kontrolerze: $controller, w akcji: $action");
    }

}

?>